package logger

import (
	"context"
	"time"

	"go.uber.org/zap"
)

func (l *logger) Debug(ctx context.Context, v string, msg ...any) {
	l.check()
	values := l.context(ctx)
	l.print(DebugLevel, v, values, msg)
}

func (l *logger) Info(ctx context.Context, v string, msg ...any) {
	l.check()
	values := l.context(ctx)
	l.print(InfoLevel, v, values, msg)
}

func (l *logger) Warn(ctx context.Context, v string, msg ...any) {
	l.check()
	values := l.context(ctx)
	l.print(WarnLevel, v, values, msg)
}

func (l *logger) Error(ctx context.Context, v string, msg ...any) {
	l.check()
	values := l.context(ctx)
	l.print(ErrorLevel, v, values, msg)
}

func (l *logger) Panic(ctx context.Context, v string, msg ...any) {
	l.check()
	values := l.context(ctx)
	l.print(PanicLevel, v, values, msg)
}

func (l *logger) check() {
	l.Channel <- struct{}{}
	defer func() { <-l.Channel }()
	if l.Target == outputBash {
		return
	}
	if !l.FileDaySplit {
		return
	}
	if l.Split == time.Now().Day() {
		return
	}
	if l.Target != outputFile {
		return
	}
	err := l.file()
	if err != nil {
		print("[logger_warning] init logger client failed:" + err.Error() + "\n")
	}
}

func (l *logger) context(ctx context.Context) []any {
	var list = make([]any, 0)
	for _, v := range l.Keys {
		value := ctx.Value(v)
		if value == nil {
			continue
		}
		list = append(list, value, l.Interval)
	}
	return list
}

func (l *logger) print(level LogLevel, v string, values, msg []any) {
	if l.Level > level {
		return
	}
	var str string
	if len(values) > 0 {
		for range len(values) {
			str += "%v"
		}
	}
	switch {
	case len(msg) > 0:
		str += v
		values = append(values, msg...)
	default:
		str += "%v"
		values = append(values, v)
	}
	var out *zap.SugaredLogger
	switch l.Target {
	case outputBash:
		out = l.Output
	default:
		switch l.FileLvSplit {
		case true:
			switch level {
			case DebugLevel:
				out = l.File.debug
			case InfoLevel:
				out = l.File.info
			case WarnLevel:
				out = l.File.warn
			case ErrorLevel:
				out = l.File.error
			case PanicLevel:
				out = l.File.panic
			}
		default:
			out = l.Output
		}
	}
	switch level {
	case DebugLevel:
		out.Debugf(str, values...)
	case InfoLevel:
		out.Infof(str, values...)
	case WarnLevel:
		out.Warnf(str, values...)
	case ErrorLevel:
		out.Errorf(str, values...)
	case PanicLevel:
		out.DPanicf(str, values...)
	}
}
